/*
 *  Copyright 2007-2008 by Matthias Buch-Kromann <mbk.isv@cbs.dk>.
 *  *
 *  This file is part of the Open-source Dependency Toolkit (OSDT),
 *  see http://code.google.com/p/open-source-dependency-toolkit.
 *  
 *  The OSDT is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as 
 *  published by the Free Software Foundation, either version 3 of 
 *  the License, or (at your option) any later version.
 * 
 *  The OSDT is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public 
 *  License along with the OSDT in the files COPYING and COPYING.LESSER.
 *  If not, see http://www.gnu.org/licenses.
 */

package org.osdtsystem.graphs;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.osdtsystem.functions.LocalFunction;

/**
 * A representation of the context in which a graph function is evaluated. 
 * Any variables that are defined during the evaluation of the function are
 * stored in the evaluation context, and so is the evaluation path that is used
 * to check for cyclicity.
 * @author Matthias Buch-Kromann <mbk.isv@cbs.dk>
 */
public class FunctionContext  {
    private Set<LocalFunction> visited;
    List<String> variables = new ArrayList<String>();
    List<Object> values = new ArrayList<Object>();
    
    // Constructor
    FunctionContext() {
    }
       
    // Variables
    public Object variable(String name) {
        int i = variables.lastIndexOf(name);
        return (i >= 0) ? values.get(i) : null;
    }
    
    public void pushVariable(String name, Object value) {
        variables.add(name);
        values.add(value);
    }
    
    public void popVariable() {
        variables.remove(variables.size() - 1);
        values.remove(values.size() - 1);
    }
    
    public void restoreState(int size) {
        for (int i = variables.size() - size; i > 0; --i)
            popVariable();
    }
    
    public int state() {
        return variables.size();
    }
    
    // Cycle detection
    public boolean exploring(LocalFunction lf) {
        return visited == null ? false : visited.contains(lf);
    }
    
    public boolean explore(LocalFunction lf) {
        // Create list of visited external functions if non-existent
        if (visited == null)
            visited = new HashSet<LocalFunction>();
        
        // Return true if the local function has been visited already
        if (visited.contains(lf))
            return false;
        
        // Otherwise, add local function to visited functions
        visited.add(lf);
        return true;
    }
    
    public void leave(LocalFunction lf) {
        if (visited != null)
            visited.remove(lf);
    }
    
    public static String ThisLocationVariableName = "_THIS";
    public static String ThisEdgeVariableName = "_ETHIS";
    public static String ThisNodeVariableName = "_NTHIS";
}
